#include "GroupEntry.h"

#include "EventNetwork.h"
#include "MemberManager.h"

#include <libintl.h>
#define _(String) gettext(String)

static guint group_disappear_signal;

struct _GroupEntry
{
	AdwBin parent_instance;
	//
	GtkFrame  *group_frame;
	GtkLabel  *group_name;
	GtkLabel  *group_id_string;
	GtkButton *user_set_button;
	GtkButton *group_set_button;
	GtkButton *quit_button;
	//
	AdwDialog      *group_set_dialog;
	AdwAlertDialog *confirm_quit_dialog;
	//
	AdwEntryRow    *group_name_entry;
	AdwSwitchRow   *writable_switch;
	AdwSwitchRow   *joinable_switch;
	AdwAlertDialog *real_group_delete_dialog;
	//
	AdwAlertDialog *alert_with_error_dialog;
	//
	GtkGesture *mouse_clicker;
	//
	euint32 group_id;
	bool	global_can_write;
	bool	can_join;
	bool	is_close_due_to_delete;
	//
	bool is_creator;
	bool can_write;
	bool is_selected;
};

GroupEntry *last_group_entry = NULL;

G_DEFINE_FINAL_TYPE(GroupEntry, group_entry, ADW_TYPE_BIN)

static void
group_single_click(GroupEntry *self, gpointer data)
{
	static const char *add_css[]  = { "entry-select-leave", NULL };
	static const char *remove_css = "entry-select-leave";
	g_return_if_fail(self != NULL);

	self->is_selected = !self->is_selected;

	if (last_group_entry && (last_group_entry != self)) {
		gtk_widget_remove_css_class(
			GTK_WIDGET(last_group_entry->group_frame), remove_css);
		last_group_entry->is_selected = false;
	}

	if (self->is_selected) {
		gtk_widget_set_css_classes(GTK_WIDGET(self->group_frame),
					   add_css);
		last_group_entry = self;
	} else {
		gtk_widget_remove_css_class(GTK_WIDGET(self->group_frame),
					    remove_css);
		last_group_entry = NULL;
	}
}

GtkWidget *
group_entry_new(void)
{
	return g_object_new(GROUP_TYPE_ENTRY, NULL);
}

void
group_entry_set_group_name(GroupEntry *self, const char *group_name)
{
	g_return_if_fail(self != NULL);
	gtk_label_set_label(self->group_name, group_name);
}

const char *
group_entry_get_group_name(GroupEntry *self)
{
	g_return_val_if_fail(self != NULL, NULL);
	return gtk_label_get_label(self->group_name);
}

const char *
group_entry_get_group_id_str(GroupEntry *self)
{
	g_return_val_if_fail(self != NULL, NULL);
	return gtk_label_get_label(self->group_id_string);
}

euint32
group_entry_get_group_id(GroupEntry *self)
{
	g_return_val_if_fail(self != NULL, 0);
	return self->group_id;
}

void
group_entry_set_group_id(GroupEntry *self, euint32 group_id)
{
	static char buffer[20];
	g_return_if_fail(self != NULL);
	self->group_id = group_id;
	sprintf(buffer, "%07d", group_id);
	gtk_label_set_label(self->group_id_string, buffer);
}

void
group_entry_set_can_write(GroupEntry *self, bool can_write)
{
	g_return_if_fail(self != NULL);
	self->can_write = can_write;
}

void
group_entry_set_is_creator(GroupEntry *self, bool is_creator)
{
	g_return_if_fail(self != NULL);
	self->is_creator = is_creator;
	if (is_creator) {
		self->can_write = true;
		gtk_widget_set_sensitive(GTK_WIDGET(self->user_set_button),
					 true);
		gtk_widget_set_visible(GTK_WIDGET(self->quit_button), false);
		gtk_widget_set_visible(GTK_WIDGET(self->group_set_button),
				       true);
	} else {
		gtk_widget_set_sensitive(GTK_WIDGET(self->user_set_button),
					 false);
		gtk_widget_set_visible(GTK_WIDGET(self->group_set_button),
				       false);
		gtk_widget_set_visible(GTK_WIDGET(self->quit_button), true);
	}
}

void
group_entry_set_can_join(GroupEntry *self, bool can_join)
{
	g_return_if_fail(self != NULL);
	adw_switch_row_set_active(ADW_SWITCH_ROW(self->joinable_switch),
				  can_join);
	self->can_join = can_join;
}

void
group_entry_set_global_can_write(GroupEntry *self, bool g_can_write)
{
	g_return_if_fail(self != NULL);
	adw_switch_row_set_active(ADW_SWITCH_ROW(self->writable_switch),
				  g_can_write);
	self->global_can_write = g_can_write;
}

bool
group_entry_verify_can_modify(GroupEntry *self)
{
	g_return_val_if_fail(self != NULL, false);
	return self->can_write;
}

static void
quit_group_action_cb(GroupEntry *self, gpointer data)
{
	adw_alert_dialog_format_body(self->confirm_quit_dialog,
				     _("Group \"%s\" will be quit."),
				     gtk_label_get_label(self->group_name));
	adw_dialog_present(ADW_DIALOG(self->confirm_quit_dialog),
			   GTK_WIDGET(self));
}

static void
confirm_quit_cb(GroupEntry *self, gchar *response, gpointer data)
{
	ResponseType re_type;
	if (g_str_equal(response, "cancel"))
		return;

	re_type = event_network_quit_group(event_network, self->group_id);
	switch (re_type) {
	case RESPONSE_TYPE_SUCCESS:
		g_signal_emit(self, group_disappear_signal, 0);
		break;
	case RESPONSE_TYPE_NONE:
		adw_alert_dialog_set_body(
			self->alert_with_error_dialog,
			event_network_get_error_info(event_network));
		adw_dialog_present(ADW_DIALOG(self->alert_with_error_dialog),
				   GTK_WIDGET(self));
		break;
	default:
		adw_alert_dialog_set_body(self->alert_with_error_dialog,
					  _(response_type[re_type]));
		adw_dialog_present(ADW_DIALOG(self->alert_with_error_dialog),
				   GTK_WIDGET(self));
		break;
	}
}

static void
group_set_cb(GroupEntry *self, gpointer data)
{
	gtk_editable_set_text(GTK_EDITABLE(self->group_name_entry),
			      gtk_label_get_label(self->group_name));
	group_entry_set_global_can_write(self, self->global_can_write);
	group_entry_set_can_join(self, self->can_join);
	adw_dialog_present(self->group_set_dialog, GTK_WIDGET(self));
}

static void
member_set_cb(GroupEntry *self, gpointer data)
{
	MemberManager *manager_dialog = member_manager_new(self->group_id);
	member_manager_fetch_all_member(manager_dialog);
	adw_dialog_present(ADW_DIALOG(manager_dialog), GTK_WIDGET(self));
}

static void
real_group_delete_cb(GroupEntry *self, gchar *response, AdwAlertDialog *dialog)
{
	ResponseType re_type;
	if (g_str_equal(response, "cancel"))
		return;
	re_type = event_network_remove_group(event_network, self->group_id);
	switch (re_type) {
	case RESPONSE_TYPE_NONE:
		adw_alert_dialog_set_body(
			self->alert_with_error_dialog,
			event_network_get_error_info(event_network));
		adw_dialog_present(ADW_DIALOG(self->alert_with_error_dialog),
				   GTK_WIDGET(self));
		break;
	case RESPONSE_TYPE_SUCCESS:
		g_signal_emit(self, group_disappear_signal, 0);
		break;
	default:
		adw_alert_dialog_set_body(self->alert_with_error_dialog,
					  _(response_type[re_type]));
		adw_dialog_present(ADW_DIALOG(self->alert_with_error_dialog),
				   GTK_WIDGET(self));
		break;
	}
	//
	self->is_close_due_to_delete = true;
	adw_dialog_close(ADW_DIALOG(dialog));
	adw_dialog_close(ADW_DIALOG(self->group_set_dialog));
}

static void
delete_group_click_cb(GroupEntry *self, gpointer data)
{
	adw_alert_dialog_format_body(
		self->real_group_delete_dialog,
		_("Are you sure you want to delete group '%s'? All events and "
		  "user data of this group will be lost!"),
		gtk_label_get_label(self->group_name));
	adw_dialog_present(ADW_DIALOG(self->real_group_delete_dialog),
			   GTK_WIDGET(self));
}

static void
group_name_modify_cb(GroupEntry *self, AdwEntryRow *group_name_entry)
{
	ResponseType re_type;
	re_type = event_network_modify_group_name(
		event_network, self->group_id,
		gtk_editable_get_text(GTK_EDITABLE(group_name_entry)));
	switch (re_type) {
	case RESPONSE_TYPE_NONE:
		adw_alert_dialog_set_body(
			self->alert_with_error_dialog,
			event_network_get_error_info(event_network));
		adw_dialog_present(ADW_DIALOG(self->alert_with_error_dialog),
				   GTK_WIDGET(self));
		break;
	case RESPONSE_TYPE_SUCCESS:
		group_entry_set_group_name(
			self,
			gtk_editable_get_text(GTK_EDITABLE(group_name_entry)));
		break;
	default:
		adw_alert_dialog_set_body(self->alert_with_error_dialog,
					  _(response_type[re_type]));
		adw_dialog_present(ADW_DIALOG(self->alert_with_error_dialog),
				   GTK_WIDGET(self));
		break;
	}
}

static void
group_set_dialog_close_modify_cb(GroupEntry *self, gpointer data)
{
	ResponseType re_type;
	bool	     global_can_write, can_join;
	global_can_write = adw_switch_row_get_active(self->writable_switch);
	can_join	 = adw_switch_row_get_active(self->joinable_switch);
	//
	if (global_can_write == self->global_can_write)
		goto detect_join_flag_change;
	re_type = event_network_modify_g_can_write(
		event_network, self->group_id, global_can_write);
	switch (re_type) {
	case RESPONSE_TYPE_NONE:
		adw_alert_dialog_set_body(
			self->alert_with_error_dialog,
			event_network_get_error_info(event_network));
		adw_dialog_present(ADW_DIALOG(self->alert_with_error_dialog),
				   GTK_WIDGET(self));
		goto close_change;
	case RESPONSE_TYPE_SUCCESS:
		group_entry_set_global_can_write(self, global_can_write);
		break;
	default:
		adw_alert_dialog_set_body(self->alert_with_error_dialog,
					  _(response_type[re_type]));
		adw_dialog_present(ADW_DIALOG(self->alert_with_error_dialog),
				   GTK_WIDGET(self));
		goto close_change;
	}
detect_join_flag_change:
	if (can_join == self->can_join)
		goto close_change;
	re_type = event_network_modify_can_join(event_network, self->group_id,
						can_join);
	switch (re_type) {
	case RESPONSE_TYPE_NONE:
		adw_alert_dialog_set_body(
			self->alert_with_error_dialog,
			event_network_get_error_info(event_network));
		adw_dialog_present(ADW_DIALOG(self->alert_with_error_dialog),
				   GTK_WIDGET(self));
		goto close_change;
	case RESPONSE_TYPE_SUCCESS:
		group_entry_set_can_join(self, can_join);
		break;
	default:
		adw_alert_dialog_set_body(self->alert_with_error_dialog,
					  _(response_type[re_type]));
		adw_dialog_present(ADW_DIALOG(self->alert_with_error_dialog),
				   GTK_WIDGET(self));
		goto close_change;
	}
close_change:
	//
	self->is_close_due_to_delete = false;
}

static void
alert_error_close_cb(AdwAlertDialog *self, gchar *response, gpointer data)
{
	adw_dialog_close(ADW_DIALOG(self));
}

static void
group_entry_finalize(GObject *object)
{
	g_object_unref(GROUP_ENTRY(object)->mouse_clicker);
	G_OBJECT_CLASS(group_entry_parent_class)->finalize(object);
}

static void
group_entry_class_init(GroupEntryClass *klass)
{
	GObjectClass   *object_class = G_OBJECT_CLASS(klass);
	GtkWidgetClass *widget_class = GTK_WIDGET_CLASS(klass);

	gtk_widget_class_set_template_from_resource(
		widget_class, "/org/korack/event/ui/GroupEntry.ui");
	gtk_widget_class_bind_template_child(widget_class, GroupEntry,
					     group_frame);
	gtk_widget_class_bind_template_child(widget_class, GroupEntry,
					     group_name);
	gtk_widget_class_bind_template_child(widget_class, GroupEntry,
					     group_id_string);
	gtk_widget_class_bind_template_child(widget_class, GroupEntry,
					     user_set_button);
	gtk_widget_class_bind_template_child(widget_class, GroupEntry,
					     group_set_button);
	gtk_widget_class_bind_template_child(widget_class, GroupEntry,
					     quit_button);
	gtk_widget_class_bind_template_child(widget_class, GroupEntry,
					     group_set_dialog);
	gtk_widget_class_bind_template_child(widget_class, GroupEntry,
					     confirm_quit_dialog);
	gtk_widget_class_bind_template_child(widget_class, GroupEntry,
					     group_name_entry);
	gtk_widget_class_bind_template_child(widget_class, GroupEntry,
					     writable_switch);
	gtk_widget_class_bind_template_child(widget_class, GroupEntry,
					     joinable_switch);
	gtk_widget_class_bind_template_child(widget_class, GroupEntry,
					     real_group_delete_dialog);
	gtk_widget_class_bind_template_child(widget_class, GroupEntry,
					     alert_with_error_dialog);

	gtk_widget_class_bind_template_callback(widget_class, group_set_cb);
	gtk_widget_class_bind_template_callback(widget_class, member_set_cb);
	gtk_widget_class_bind_template_callback(widget_class,
						quit_group_action_cb);
	gtk_widget_class_bind_template_callback(widget_class, confirm_quit_cb);
	gtk_widget_class_bind_template_callback(widget_class,
						delete_group_click_cb);
	gtk_widget_class_bind_template_callback(widget_class,
						group_name_modify_cb);
	gtk_widget_class_bind_template_callback(widget_class,
						real_group_delete_cb);
	gtk_widget_class_bind_template_callback(
		widget_class, group_set_dialog_close_modify_cb);
	gtk_widget_class_bind_template_callback(widget_class,
						alert_error_close_cb);

	group_disappear_signal = g_signal_newv(
		"quit", G_TYPE_FROM_CLASS(object_class),
		G_SIGNAL_RUN_LAST | G_SIGNAL_NO_RECURSE | G_SIGNAL_NO_HOOKS,
		NULL, NULL, NULL, NULL, G_TYPE_NONE, 0, NULL);

	G_OBJECT_CLASS(klass)->finalize = group_entry_finalize;
}

static void
group_entry_init(GroupEntry *self)
{
	gtk_widget_init_template(GTK_WIDGET(self));
	self->group_id		     = 0;
	self->is_creator	     = false;
	self->is_selected	     = false;
	self->can_write		     = false;
	self->can_join		     = false;
	self->global_can_write	     = false;
	self->is_close_due_to_delete = false;

	/* 鼠标单击 */
	self->mouse_clicker = gtk_gesture_click_new();
	gtk_gesture_single_set_button(GTK_GESTURE_SINGLE(self->mouse_clicker),
				      1);
	gtk_widget_add_controller(GTK_WIDGET(self),
				  GTK_EVENT_CONTROLLER(self->mouse_clicker));
	g_signal_connect_swapped(self->mouse_clicker, "released",
				 G_CALLBACK(group_single_click), self);
}
